/*
 * ksCatalogAtomBlockWriter.cpp
 *
 *  Created on: 2011-8-13
 *      Author: wangchao
 */

#include "ksCatalogAtomBlockWriter.h"
#include <iostream>
#include <sstream>
#include <fstream>

#include <cstddef>
#include "../ksException.h"
#include "../ksBlockEntry.h"

using namespace std;

unsigned int ksCatalogEntry::dataSize()
{
    if (_type == EVolume)
    {
        return sizeof(unsigned char) // type
        + sizeof(unsigned char) // title length
        + _title.length(); // title content
    }
    else if (_type == EChapter)
    {
        return sizeof(unsigned char) // type
        + sizeof(_offset) // offset
        + sizeof(unsigned char) // title length
        + _title.length(); // title content
    }
    else
    {
        throw ksException("not except catalog type");
    }
}

void ksCatalogEntry::save(std::ofstream & out)
{
    if (_type == EVolume)
    {
        out.write((char*) &_type, sizeof(_type));

        if (_title.length() > 255)
        {
            throw ksException("title to long");
        }
        unsigned char length = (unsigned char) _title.length();
        out.write((char*) &length, sizeof(length));
        out.write(_title.c_str(), length);
    }
    else if (_type == EChapter)
    {
        out.write((char*) &_type, sizeof(_type));

        out.write((char*) &_offset, sizeof(_offset));
        if (_title.length() > 255)
        {
            throw ksException("title to long");
        }

        unsigned char length = (unsigned char) _title.length();
        out.write((char*) &length, sizeof(length));
        out.write(_title.c_str(), length);
    }
    else
    {
        throw ksException("not except catalog type");
    }
}

ksCatalogAtomBlockWriter::ksCatalogAtomBlockWriter()
{

}

ksCatalogAtomBlockWriter::~ksCatalogAtomBlockWriter()
{

}

unsigned int ksCatalogAtomBlockWriter::blockLength()
{
    return _blockHeader.atom.dataLength + kAtomBlockHeaderLength;
}
/*
 * 解析如下格式的目录信息
 volume:{title:卷一}
 chapter:{title:第一章, resource:1.zip }
 chapter:{title:第二章, resource:2.zip }
 volume:{title:卷二}
 chapter:{title:第三章, resource:3.zip }
 chapter:{title:第四章, resource:4.zip }
 volume:{title:卷三}
 chapter:{title:第五章, resource:5.zip }
 chapter:{title:第六章, resource:6.zip }
 */

#define kVolumeTag "volume:"
const int kVolumeTagLength = sizeof(kVolumeTag) - 1;
#define kChapterTag "chapter:"
const int kChapterTagLength = sizeof(kChapterTag) - 1;
#define kTitleTag "title:"
const int kTitleTagLength = sizeof(kTitleTag) - 1;
#define kResourceTag "resource:"
const int kResourceTagLength = sizeof(kResourceTag) - 1;

bool tagExist(const string& content, const string& tag, int beginPos, size_t& result)
{
    result = content.find(tag, beginPos);
    if (result != string::npos)
    {
        result += tag.length();
        return true;
    }
    return false;
}

string tagContent(const string& content, const string&tag, const string& closeTag, int beginpos, size_t& result)
{
    result = string::npos;

    size_t tagBegin = content.find(tag, beginpos);
    if (tagBegin != string::npos)
    {
        size_t closePosition = content.find(closeTag, tagBegin + tag.length());
        if (closePosition != string::npos)
        {
            int begin = tagBegin + tag.length();
            int count = closePosition - begin;
            result = closePosition;
            return content.substr(begin, count);
        }
    }

    return string("");
}

void ksCatalogAtomBlockWriter::setData(unsigned char *data, unsigned int length)
{
    stringstream stream(string((char*) data, length));

    char buffer[256] = { 0 };
    while (stream.good())
    {
        ksCatalogEntry* entry = NULL;
        stream.getline(buffer, 256);
        string line(buffer);

        size_t volumePosition = string::npos;
        size_t chapterPosition = string::npos;
        size_t titlePosition = string::npos;
        size_t resourcePosition = string::npos;
        if (tagExist(line, kVolumeTag, 0, volumePosition))
        {
            string title = tagContent(line, kTitleTag, "}", volumePosition, titlePosition);
            if (titlePosition != string::npos)
            {
                entry = new ksCatalogEntry();
                entry->_type = ksCatalogEntry::EVolume;
                entry->_title = title;
                _entries.push_back(entry);
            }
            else
            {
                throw ksException("not found title tag:\"title\" ");
            }
        }
        else if (tagExist(line, kChapterTag, 0, chapterPosition))
        {
            string title = tagContent(line, kTitleTag, ",", chapterPosition, titlePosition);
            if (titlePosition != string::npos)
            {
                string resource = tagContent(line, kResourceTag, "}", titlePosition, resourcePosition);
                if (resourcePosition != string::npos)
                {
                    entry = new ksCatalogEntry();
                    entry->_type = ksCatalogEntry::EChapter;
                    entry->_resource = resource;
                    entry->_title = title;
                    _entries.push_back(entry);
                }
                else
                {
                    Log( "not found resource tag:\"resource\" ");
                }
            }
            else
            {
                throw ksException("not found title tag:\"title\" ");

            }
        }
        else
        {
            throw ksException("not except catalog type");
        }
    }
    std::vector<ksCatalogEntry*>::iterator it = _entries.begin();
    for (; it != _entries.end(); it++)
    {
        _blockHeader.atom.dataLength += (*it)->dataSize();
    }
// _blockHeader.atom.dataLength = length;
// _data = data;
    delete[] data;
    _data = NULL;
}

void ksCatalogAtomBlockWriter::save(std::ofstream & out)
{
    LogObj("");
    description();
    std::cout << "ksCatalogAtomBlockWriter::save write at:" << out.tellp();
    // save header
    out.write((char*) &_blockHeader.atom, sizeof(_atomBlockHeader));
    std::cout << " header end:" << out.tellp();

    // save data
    std::vector<ksCatalogEntry*>::iterator it = _entries.begin();
    for (; it != _entries.end(); it++)
    {
        (*it)->save(out);
    }
    std::cout << " :end:" << out.tellp();
    // write padding
    char padding[4] = { 0 };
    int paddingLength = _align4(_blockHeader.atom.dataLength) - _blockHeader.atom.dataLength;
    if (paddingLength != 0)
    {
        out.write(padding, paddingLength);
    }
    std::cout << " :padding:" << out.tellp() << std::endl;
}

void ksCatalogAtomBlockWriter::updateResourceID(const std::string & resource, int resourceId)
{
    std::vector<ksCatalogEntry*>::iterator it = _entries.begin();
    for (; it != _entries.end(); it++)
    {
        if ((*it)->_resource == resource)
        {
            (*it)->_resourceId = resourceId;
            break;
        }
    }
}

void ksCatalogAtomBlockWriter::updateEntryOffset(const ksBlockEntry& entry, int offsetInFile)
{
    std::vector<ksCatalogEntry*>::iterator it = _entries.begin();
    for (; it != _entries.end(); it++)
    {
        if ((*it)->_resourceId == entry.id())
        {
            (*it)->_offset = entry.offset() + offsetInFile;
            break;
        }
    }
}

